#include <stdio.h>
#include <string.h>

#include "E32_433T33S.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"

#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "iot_board.h"

#define UART_BUF_SIZE        (128)
#define PACKET_READ_TICS        (100 / portTICK_PERIOD_MS)
const char *TAG="E32";

/**
 * Name:    hw_read
 * Brief:   硬件层接收数据
 * Input:
 *  @ctx:   645运行环境
 *  @msg:   接收数据存放地址
 *  @len:   数据最大接收长度 
 * Output:  读取数据的长度
 */
int e32_port_read(e32_handle_t handle, uint8_t *msg ,uint16_t len)
{
    //实际接收长度
    int read_len = 0;
    read_len = uart_read_bytes(handle->uart_num, msg, len, PACKET_READ_TICS);
	//ESP_LOGI(TAG, "uart read len %d", read_len);
	//dump(msg, read_len);
    return read_len;
}

/**
 * Name:    e32_hw_write
 * Brief:   e32_handle 硬件层发送数据
 * Input:
 *  @ctx:   645运行环境
 *  @buf:   待发送数据
 *  @len:   发送长度
 * Output:  实际发送的字节数，错误返回-1
 */
int e32_port_write(e32_handle_t handle, uint8_t *buf, uint16_t len)
{
	// 清空接收缓存
	// uart_flush_input(handle->uart_num);
    //串口发送数据
    return uart_write_bytes(handle->uart_num,buf,len);
}


//645采集硬件层修改波特率
int e32_port_set_baudrate(e32_handle_t handle, int baudrate)
{
	uint32_t now_baudrate;
	ESP_ERROR_CHECK(uart_get_baudrate(handle->uart_num, &now_baudrate));
	if(now_baudrate != baudrate){
	    // Configure UART parameters
	    ESP_ERROR_CHECK(uart_set_baudrate(handle->uart_num, baudrate));
	}

	return	0;

}
//645采集硬件层修改校验位
int e32_port_set_parity(e32_handle_t handle, int val)
{
	uart_parity_t parity_mode;

	ESP_ERROR_CHECK(uart_get_parity(handle->uart_num, &parity_mode));
	if(parity_mode != (uart_parity_t)val){
	    // Configure UART parameters
	    ESP_ERROR_CHECK(uart_set_parity(handle->uart_num, val));
	}
	return	0;

}

/**
 * Name:    e32_uart_event_task
 * Brief:   e32 uart 事件处理任务
 * Input:
 *  @ctx:   运行环境
 *  @timeout:   等待时间ms
 * Output:  0:收到数据,-1:超时
 */
int e32_uart_event_task(e32_handle_t handle, int timeout)
{
    int ret = -1;
    uart_event_t event;
    if(xQueueReceive(handle->uart_queue, (void * )&event, pdMS_TO_TICKS(timeout))) {
        memset(handle->rx_buf, 0, UART_BUF_SIZE);
        ESP_LOGI(TAG, "uart [%d] event:", handle->uart_num);
        switch(event.type) {
            //Event of UART receving data
            /*We'd better handler data event fast, there would be much more data events than
            other types of events. If we take too much time on data event, the queue might
            be full.*/
            case UART_DATA:
                ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                uart_read_bytes(handle->uart_num, handle->rx_buf, event.size, portMAX_DELAY);
                if(handle->mode == E32_MODE_SLEEP) {
                    // 休眠模式下接收配置信息
                    if(handle->rx_buf[0] == 0xC0) {
                        // 工作参数读取
                        handle->params.addr = (handle->rx_buf[1] << 8) | handle->rx_buf[2];
                        handle->params.speed = handle->rx_buf[3];
                        handle->params.channel = handle->rx_buf[4];
                        handle->params.option = handle->rx_buf[5];
                        ESP_LOGD(TAG, "addr: %"PRIX16", speed: %"PRIX8", channel: %"PRIX8", option: %"PRIX8"", 
                                handle->params.addr, handle->params.speed, handle->params.channel, handle->params.option);
                    }
                    else if(handle->rx_buf[0] == 0xC3) {
                        // 版本号读取
                        handle->version.model = handle->rx_buf[1];
                        handle->version.version = handle->rx_buf[2];
                        handle->version.interface = handle->rx_buf[3];
                        ESP_LOGD(TAG, "model: %"PRIX8", version: %"PRIX8", interface: %"PRIX8"", 
                                handle->version.model, handle->version.version, handle->version.interface);
                    }
                }
                else if(handle->recv_handle){
                    handle->recv_handle(handle, handle->rx_buf, event.size);
                }
                ret = 0;
                break;
            //Event of HW FIFO overflow detected
            case UART_FIFO_OVF:
                ESP_LOGI(TAG, "hw fifo overflow");
                // If fifo overflow happened, you should consider adding flow control for your application.
                // The ISR has already reset the rx FIFO,
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(handle->uart_num);
                xQueueReset(handle->uart_queue);
                break;
            //Event of UART ring buffer full
            case UART_BUFFER_FULL:
                ESP_LOGI(TAG, "ring buffer full");
                // If buffer full happened, you should consider encreasing your buffer size
                // As an example, we directly flush the rx buffer here in order to read more data.
                uart_flush_input(handle->uart_num);
                xQueueReset(handle->uart_queue);
                break;
            //Event of UART RX break detected
            case UART_BREAK:
                ESP_LOGI(TAG, "uart rx break");
                break;
            //Event of UART parity check error
            case UART_PARITY_ERR:
                ESP_LOGI(TAG, "uart parity error");
                break;
            //Event of UART frame error
            case UART_FRAME_ERR:
                ESP_LOGI(TAG, "uart frame error");
                break;
            //Others
            default:
                ESP_LOGI(TAG, "uart event type: %d", event.type);
                break;
        }
    }
    return ret;
}

int e32_port_create(e32_port_config_t *cfg, e32_handle_t *out_handle)
{
	if(NULL == cfg || NULL == out_handle)
		return ESP_FAIL;
	
    e32_struct_t *e32_handle = (e32_struct_t *) calloc(1, sizeof(e32_struct_t));
    // e32_handle->mode = E32_433T33S_MODE_SLEEP;
    //串口初始化
    e32_handle->uart_num = cfg->uart_num;
    uart_config_t uart_config = {
        .baud_rate = cfg->baud_rate,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        // .rx_flow_ctrl_thresh = 122,
        .source_clk = UART_SCLK_APB,
    };

    ESP_LOGI(TAG, "Start RS485 application test and configure UART.");

    // Install UART driver (we don't need an event queue here)
    // In this example we don't even use a buffer for sending data.
    ESP_ERROR_CHECK(uart_driver_install(e32_handle->uart_num, UART_BUF_SIZE*2, UART_BUF_SIZE*2, 5, &e32_handle->uart_queue, (ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)));

    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(e32_handle->uart_num, &uart_config));

    ESP_LOGI(TAG, "UART set pins, mode and install driver.");

    // Set UART pins as per KConfig settings
    ESP_ERROR_CHECK(uart_set_pin(e32_handle->uart_num, cfg->tx_io_num, cfg->rx_io_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

    // Set RS485 half duplex mode
    ESP_ERROR_CHECK(uart_set_mode(e32_handle->uart_num, UART_MODE_UART));

	// if(UART_MODE_RS485_HALF_DUPLEX == cfg->mode){
	//     // Set read timeout of UART TOUT feature
	//     ESP_ERROR_CHECK(uart_set_rx_timeout(e32_handle->uart_num, RS485_READ_TOUT));
	// }

    // if(cfg->aux_io_num > 0){
    //     gpio_config_t gpio_conf;
    //     gpio_conf.intr_type = GPIO_INTR_DISABLE;
    //     gpio_conf.mode = GPIO_MODE_INPUT;
    //     gpio_conf.pin_bit_mask = (1ULL << cfg->aux_io_num);
    //     gpio_conf.pull_down_en = GPIO_PULLUP_DISABLE;
    //     gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    //     gpio_config(&gpio_conf);
    //     e32_handle->aux_io_num = cfg->aux_io_num;
    // }
    // if(cfg->mode_io_num > 0) {
    //     gpio_config_t gpio_conf;
    //     gpio_conf.intr_type = GPIO_INTR_DISABLE;
    //     gpio_conf.mode = GPIO_MODE_OUTPUT;
    //     gpio_conf.pin_bit_mask = (1ULL << cfg->mode_io_num);
    //     gpio_conf.pull_down_en = GPIO_PULLUP_DISABLE;
    //     gpio_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    //     gpio_config(&gpio_conf);
    //     e32_handle->mode_io_num = cfg->mode_io_num;
    // }

    if(e32_handle->rx_buf == NULL){
        e32_handle->rx_buf = calloc(UART_BUF_SIZE, sizeof(char));
    }
    *out_handle = e32_handle;
    return  0;
}

int e32_port_destroy(e32_handle_t *handle) {
    // Uninstall UART driver
    ESP_ERROR_CHECK(uart_driver_delete((*handle)->uart_num));
    // Free memory
    free(*handle);
    *handle = NULL;
    return 0;
}

void e32_set_aux_status(e32_handle_t handle, bool status) {
    handle->aux_status = status;
}

bool e32_get_aux_status(e32_handle_t handle) {
    return handle->aux_status;
}

int e32_set_mode(e32_handle_t handle, e32_mode_t mode) {

    if(handle){
        handle->mode = mode;
    }
    switch (mode)
    {
    case E32_MODE_NORMAL:
        iot_board_led_set_state(BOARD_IO_E32_MD0, 0);
        iot_board_led_set_state(BOARD_IO_E32_MD1, 0);
        break;
    case E32_MODE_WOR_1:
        iot_board_led_set_state(BOARD_IO_E32_MD0, 1);
        iot_board_led_set_state(BOARD_IO_E32_MD1, 0);
        break;
    case E32_MODE_WOR_2:
        iot_board_led_set_state(BOARD_IO_E32_MD0, 0);
        iot_board_led_set_state(BOARD_IO_E32_MD1, 1);
        break;
    case E32_MODE_SLEEP:
        iot_board_led_set_state(BOARD_IO_E32_MD0, 1);
        iot_board_led_set_state(BOARD_IO_E32_MD1, 1);
        break;
    default:
        return -1;
    }
    return 0;
}

int e32_set_params(e32_handle_t handle, e32_params_t *params) {
    uint8_t data[6];
    data[0] = 0xC0;
    data[1] = params->addr >> 8;
    data[2] = params->addr & 0xFF;
    data[3] = params->speed;
    data[4] = params->channel;
    data[5] = params->option;
    if( 0 > e32_port_write(handle, data, sizeof(data))) {
        return -1;
    }

    return 0;
}


int e32_get_params(e32_handle_t handle, e32_params_t *params) {
    uint8_t data[3];
    data[0] = 0xC1;
    data[1] = 0xC1;
    data[2] = 0xC1;
    if( 0 > e32_port_write(handle, data, sizeof(data))) {
        return -1;
    }

    for(int i = 0; i < 5; i++){
        if( 0 == e32_uart_event_task( handle, 100)) {
            if(params!= NULL) {
                memcpy(params, &handle->params, sizeof(e32_params_t));
            }
            return 0;
        }
    }
    return -1;
}

int e32_get_version(e32_handle_t handle, e32_version_t *version) {
    uint8_t data[3];
    data[0] = 0xC3;
    data[1] = 0xC3;
    data[2] = 0xC3;
    if( 0 > e32_port_write(handle, data, sizeof(data))) {
        return -1;
    }
    for(int i = 0; i < 5; i++){
        if( 0 == e32_uart_event_task( handle, 100)) {
            if(version!= NULL) {
                memcpy(version, &handle->version, sizeof(e32_version_t));
            }
            return 0;
        }
    }

    return -1;
}

int e32_reset(e32_handle_t handle) {
    uint8_t data[3];
    data[0] = 0xC4;
    data[1] = 0xC4;
    data[2] = 0xC4;
    if( 0 > e32_port_write(handle, data, sizeof(data))) {
        return -1;
    }

    return 0;
}
